<template>
  <div id="content" ref="content">
    <div class="echartsToolBox">
      <!-- 刷新图表 -->
      <el-tooltip v-if="props.isRefreshTool" effect="dark" placement="bottom" content="刷新图表">
        <el-icon class="iconRefresh" @click="handleRefresh">
          <Refresh></Refresh>
        </el-icon>
      </el-tooltip>
    </div>

    <div
      :id="Id"
      class="chart-box"
      :style="props.noneDataZoom || props.hideDataZoom ? 'height: 100%' : 'height: calc(100% - 50px)'"
    />
  </div>
</template>

<script setup>
import { inject, nextTick, onMounted, ref, watch, onUnmounted } from 'vue'
import { uuid, Filtration, timeSlot, quchong, yAxismethod, Ycontent } from './config/index'
import { deepMerge, filterObject, typeOf } from '@/utils/cloud/utils'
import { getNowDate } from '@/utils/cloud/utils'
import { format } from 'date-fns'
import PreviewAPI from '@/api/preview'
import * as echarts from 'echarts'
import { Refresh } from '@element-plus/icons-vue'

const content = ref()
let legendSelectedParams = ref({}) // 保存图例的选中状态

const props = defineProps({
  name: {
    type: String,
    default: ''
  },
  query: {
    //主要是为了获取单位iot_id和时间间隔date
    type: Object,
    default: () => ({
      param: {
        date: [`${format(new Date(), 'yyyy-MM-dd')} 00:00:00`, `${format(new Date(), 'yyyy-MM-dd')} 23:59:59`]
      }
    })
  },
  echartType: {
    // 初始化图表类型
    type: [String, Array],
    default: 'line'
  },
  yAxis: {
    type: Object,
    default() {
      return {}
    }
  },
  option: {
    type: Object,
    default() {
      return {}
    }
  },
  theme: {
    type: String,
    default: '#fff' // dark
  },
  height: {
    type: String,
    default: ''
  },
  xAxis: {
    type: Object,
    default() {
      return {}
    }
  },
  hideDataZoom: {
    type: Boolean,
    default: false
  },
  noneDataZoom: {
    type: Boolean,
    default: false
  },
  hidetoolbox: {
    type: Boolean,
    default: false
  },
  hidelegend: {
    type: Boolean,
    default: false
  },
  connectNulls: {
    //断点连线
    type: Boolean,
    default: true
  },
  areaStyle: {
    //折线图填充背景
    type: Object,
    default() {
      return {
        opacity: 0
      }
    }
  },
  itemStyle: {
    //折线图填充背景
    type: Object
  },
  searchDates: {
    type: Array
  },
  // 是否进行单位换算和设置坐标轴范围
  settings: {
    type: Object
  },
  showYSplitLine: {
    type: [Boolean, Number],
    default: false
  },
  markArea: {
    type: Object,
    default: null
  },

  // 是否显示为移动端页面
  isMobile: {
    type: Boolean,
    default: false
  },
  // 是否显示下载按钮
  isDownloadTool: {
    type: Boolean,
    default: false
  },
  // 是否显示全屏按钮
  isFullScreenTool: {
    type: Boolean,
    default: false
  },
  // 是否显示刷新按钮
  isRefreshTool: {
    type: Boolean,
    default: false
  },
  // 当是微网调试页面时，图标的下载按钮、全屏按钮的位置
  specialStyle: {
    type: Boolean,
    default: false
  },
  stackName: {
    type: [String, Array],
    default: ''
  },

  // 图表的样式
  styleConfig: {
    type: Object,
    default: () => ({})
  }
})

let myChart
const Id = uuid()

//获取单位
let danwei = ref() //单位列表
const getdanwei = () => {
  return new Promise((resolve, reject) => {
    PreviewAPI.getDictionary(props.query.param.iot_id, 'iot_id').then(res => {
      if (res.code == 200) {
        danwei.value = res.msg
        resolve()
      }
    })
  })
}
const echartOption = () => {
  let dateFormat = 'HH:mm'
  if (props.query.param.date && props.query.param.date.length) {
    let str1 = props.query.param.date[0].substr(0, 10)
    let str2 = props.query.param.date[1].substr(0, 10)
    if (str1 !== str2) {
      dateFormat = 'MM-dd'
    }
  }
  //默认配置
  return {
    // title: {
    //   text: props.name,
    //   left: '2%',
    //   textStyle: {
    //     color: '#8c8c8c',
    //   },
    // },
    color: [
      '#2db7f5',
      '#ff6600',
      '#808bc6',
      '#e54d42',
      '#b2db9e',
      '#fbd88a',
      '#f39494',
      '#9dd3e8',
      '#1cbbb4',
      '#f37b1d',
      '#39b54a',
      '#fbbd08',
      '#8dc63f',
      '#2C3E50',
      '#6495ed',
      '#b0c4de',
      '#b0929f',
      '#9D2933',
      '#D24D57',
      '#EAF2D3'
    ],
    // backgroundColor: 'rgba(128, 128, 128, 0.1)',
    toolbox: {
      show: true,
      right: '0',
      top: '-6px',
      iconStyle: {
        color: themeProp.value,
        borderColor: themeProp.value
      },
      feature: {
        magicType: {
          type: ['line', 'bar'],
          title: {
            line: '切换为折线图',
            bar: '切换为柱状图'
          }
        }
        // dataZoom: {
        //   yAxisIndex: 'none',
        // },
      }
    },
    grid: {
      top: '18%',
      bottom: '4%',
      left: '5%',
      right: '6%',
      containLabel: true // 包含刻度文字在内
    },
    axisPointer: {
      link: [
        {
          xAxisIndex: 'all'
        }
      ]
    },
    tooltip: {
      trigger: 'axis',
      backgroundColor: 'rgba(255,255,255,.6)'
    },
    legend: {
      // type: 'scroll',
      type: fvisible.value ? 'plain' : 'scroll',
      width: '98%',
      data: [],
      textStyle: {
        color: themeProp.value
      },
      pageIconColor: '#a0a0a0',
      pageIconInactiveColor: '#666',
      pageTextStyle: {
        color: '#fff'
      },
      animation: true,
      pageButtonItemGap: 1,
      pageButtonGap: 10,
      selector: [
        {
          type: 'all',
          title: '全部选中'
        },
        {
          type: 'inverse',
          title: '取消选中'
        }
      ],
      selectorLabel: {
        borderWidth: '0',
        color: themeProp.value
      }
    },
    dataZoom: [
      {
        type: 'inside',
        show: true,
        start: 0,
        end: 100
      },
      {
        type: 'slider',
        show: true,
        start: 0,
        end: 100,
        height: 0,
        width: 0
      }
    ],
    xAxis: Object.keys(props.xAxis).length ? props.xAxis : timeSlot(props.query.param, dateFormat, themeProp.value),
    yAxis: Object.keys(props.yAxis).length ? props.yAxis : [],
    series: []
  }
}
const loading = ref(false)
// let opthion = {} //最后数据
// let start = ref()
// let end = ref()
let newOption
const emits = defineEmits(['finished', 'click', 'datazoom', 'exportChartData', 'emitRefresh'])
let hasData = ref(true)
const init = async opthion => {
  //触发echart
  // opthion.dataZoom[0].start = start.value
  // opthion.dataZoom[0].end = end.value
  // if (props.noneDataZoom || props.hideDataZoom) {
  //   opthion.dataZoom[0].height = 0
  //   opthion.dataZoom[0].width = 0
  // }
  newOption = deepMerge(opthion, props.option)

  if (props.hidetoolbox) {
    //删除工具栏
    delete newOption.toolbox
    delete newOption.legend.selector
    // newOption.grid.bottom = '0'
  }
  if (props.hidelegend) {
    delete newOption.legend
  }

  let dataCount = 0
  if (newOption.series && newOption.series.length) {
    dataCount = newOption.series.reduce((prev, next) => {
      return prev + next.data ? next.data.length : 0
    }, 0)
  }
  hasData.value = dataCount !== 0
  if (hasData.value) {
    setChartOption(newOption)
  } else {
    loading.value = false
  }
}

const setChartOption = option => {
  nextTick(() => {
    if (newOption && newOption.series && newOption.series.length && myChart && option) {
      if (props.markArea && !newOption.series[0].markArea) {
        newOption.series[0].markArea = props.markArea
      }
      // console.log('******', option)
      myChart.setOption(option, true)
    }
  })
}

const setLoading = (value = true) => {
  loading.value = value
}

const export_csv = (header, data, name = '设备监控数据') => {
  let csv = ''
  for (let key in header) {
    csv += header[key] + ','
  }
  csv = csv.substr(0, csv.length - 1) + '\r\n'
  for (let i in data) {
    for (let key in header) {
      csv += data[i][key] + ','
    }
    csv = csv.substr(0, csv.length - 1) + '\r\n'
  }
  let content = new Blob(['\uFEFF' + csv])
  let urlObject = window.URL || window.webkitURL || window
  let url = urlObject.createObjectURL(content)
  let el = document.createElement('a')
  el.href = url
  el.download = name + '.csv'
  el.click()
  urlObject.revokeObjectURL(url)
}
// 下载
const downloadData = name => {
  let data = []
  let header = {}
  if (newOption.xAxis.type === 'category') {
    header.category = '类目'
    newOption.series.forEach((item, index) => {
      header[item.valueName] = item.name
    })
    data = newOption.xAxis.data.map(i => {
      return {
        category: i
      }
    })
    for (const item of newOption.series) {
      data = data.map((val, index) => {
        return {
          ...val,
          [item.valueName]: item.data[index]
        }
      })
    }
  } else {
    header.time = '时间'
    newOption.series.forEach((item, index) => {
      header[item.valueName] = item.name
      if (index === 0) {
        data = item.data.map(val => {
          return {
            time: val[0],
            [item.valueName]: val[1]
          }
        })
      } else {
        data = data.map(val => {
          const findOne = item.data.find(arr => arr[0] === val.time)
          return {
            ...val,
            [item.valueName]: findOne ? findOne[1] : null
          }
        })
      }
    })
  }
  export_csv(header, data, name)
}

watch(
  () => props.echartType,
  () => {
    if (typeOf(props.echartType) === 'array') return
    newOption.series = newOption.series.map(item => {
      let obj = {
        ...item,
        type: props.echartType
      }
      return obj
    })
    setChartOption(newOption)
  }
)

const clearChart = () => {
  if (!myChart) return
  myChart.clear()
}

let transResList = (data, result) => {
  data.times.forEach((item, index) => {
    result[item] = {}
    for (let key in oldData) {
      if (key !== 'time') {
        result[item][key] = data[key][index]
      }
    }
  })
}

let oldData = {}
let oldParams = {}
const http = async (res, unit, timeParams) => {
  // 当x轴为非时间轴时, 比如（category类目轴）
  if (Object.keys(res).includes('msg_type')) {
    delete res.msg.iot_id
    const { msg_type } = res
    if (msg_type == 'query') {
      clearChart()
      oldData = res.msg
    } else if (msg_type === 'instant') {
      // newOption.series.forEach((item) => {
      //   oldData[item.valueName] = item.data.map((val) => val[1])
      // })
      // oldData.time = newOption.series[0].data.map((val) => val[0])
      if (!oldData.time || !oldData.time.length) oldData.time = []
      if (typeOf(res.msg.time) == 'array') {
        res.msg.time = res.msg.time[res.msg.time.length - 1]
      }
      if (timeParams && oldData.time.length) {
        // 起始时间和时间窗口大小
        const startTime = new Date(timeParams.start_time).getTime()
        const endTime = new Date(timeParams.end_time).getTime()
        const windowSize = timeParams.time_window * 1000 // 1800秒转换为毫秒

        // 计算时间窗口数量
        const totalWindows = Math.ceil((endTime - startTime) / windowSize)

        // 生成时间窗口数组
        const windows = Array.from({ length: totalWindows }, (_, i) => startTime + i * windowSize)

        // 获取当前时间
        const currentTime = getNowDate().getTime()

        // 找到最近的一个大于当前时间的时间窗口
        const closestWindow = windows.find(window => window > currentTime)
        res.msg.time = closestWindow ? format(new Date(closestWindow), 'yyyy-MM-dd HH:mm:ss') : res.msg.time
        // 打印结果
        // console.log(res.msg.time, res.msg)
      }
      if (
        !oldData.time.length ||
        new Date(res.msg.time).getTime() > new Date(oldData.time[oldData.time.length - 1]).getTime()
      ) {
        oldData.time.push(res.msg.time)
      } else if (new Date(res.msg.time).getTime() < new Date(oldData.time[0]).getTime()) {
        oldData.time.unshift(res.msg.time)
      } else {
        const currentTime = new Date(res.msg.time).getTime()
        const lastIndex = oldData.time.findIndex(
          (t, i) => new Date(t).getTime() < currentTime && new Date(oldData.time[i + 1]).getTime() > currentTime
        )
        if (lastIndex >= 0) {
          oldData.time.splice(lastIndex, 0, res.msg.time)
        }
      }
      let index = oldData.time.findIndex(t => t === res.msg.time)
      for (let key in oldData) {
        if (key !== 'time') {
          let current = res.msg[key]
          if (typeOf(current) == 'array') {
            current = current[current.length - 1] ? current[current.length - 1] : current[0]
          }
          if (!oldData[key]) {
            oldData[key] = []
          }

          oldData[key][index] = current || current === 0 ? current : null
        }
      }
    }
    oldParams = {
      res: {
        msg_type: 'query',
        msg: oldData
      },
      unit: unit,
      timeParams: timeParams
    }
    if (unit) {
      danwei.value = unit
    } else {
      await getdanwei()
    }
  } else {
    oldData = res
    danwei.value = unit
    oldParams = {
      res,
      unit,
      timeParams
    }
  }
  let opthion = echartOption()
  // opthion.xAxis.axisLabel?.textStyle.color = fvisible.value ? '#000' : '#fff'
  // if (props.isMobile) {
  //   opthion.xAxis.axisLabel.textStyle.color = '#fff'
  // }
  opthion.yAxis = Ycontent(
    opthion.yAxis,
    yAxismethod(
      oldData,
      danwei,
      themeProp.value,
      props.settings ? props.settings.isConversionUnits : null,
      props.settings ? props.settings.yAxisSource0 : null,
      !!props.showYSplitLine
    )
  )
  opthion.series = Filtration(oldData, danwei, props.settings ? props.settings.isConversionUnits : null).map(
    (item, index) => {
      if (props.stackName[index] && props.stackName[index].includes('stackBar')) {
        item.stack = props.stackName[index].split('-')[1] || 'total'
      }
      return Object.assign(item, {
        type: typeOf(props.echartType) == 'array' ? props.echartType[index] : props.echartType,
        connectNulls: props.connectNulls, //断点连线
        showSymbol: false,
        barMaxWidth: 15,
        areaStyle: props.areaStyle,
        itemStyle: props.itemStyle
          ? typeOf(props.itemStyle) == 'array'
            ? props.itemStyle[index]
            : props.itemStyle
          : null,
        lineStyle: props.itemStyle
          ? typeOf(props.itemStyle) == 'array'
            ? props.itemStyle[index]
            : props.itemStyle
          : null,
        symbolSize: 2
      })
    }
  )
  for (const item of opthion.series) {
    if (!item.type) {
      let name = item.name.slice(2)
      item.type = opthion.series.find(i => i.name === name).type
    }
  }
  let names = opthion.series.map(item => item.name)
  let FinalName = opthion.legend.data.concat(names)
  opthion.legend.data = [...new Set(FinalName)]
  opthion.legend.selected = legendSelectedParams.value

  // console.log('🚀 - opthion -->', opthion)
  // console.log('🚀 - styleConfig -->', props.styleConfig)
  mergeConfig(opthion, props.styleConfig)
  // console.log('🚀 - opthion -->', opthion)

  init(opthion)
}

function mergeConfig(option, styleConfig) {
  for (const key in styleConfig) {
    if (typeof styleConfig[key] === 'object' && styleConfig[key] !== null && !Array.isArray(styleConfig[key])) {
      // 如果是对象，递归合并
      if (!option[key] || typeof option[key] !== 'object') {
        option[key] = {} // 如果目标没有对应对象，初始化为对象
      }
      mergeConfig(option[key], styleConfig[key])
    } else {
      // 如果不是对象，直接覆盖
      option[key] = styleConfig[key]
    }
  }
}

const getCurrentChart = () => {
  return myChart
}
const onDatazoomChange = data => {
  emits('datazoom', data)
}
const reset = () => {
  setChartOption(newOption)
}

const themeProp = ref(props.theme)

const observer = new ResizeObserver(entries => {
  for (let entry of entries) {
    if (myChart) myChart.resize()
  }
})

const clickHandler = event => {
  emits('click', event.data)
}
const resizeHandler = () => {
  if (myChart) myChart.resize()
}

const finishedHandler = () => {
  loading.value = false
  emits('finished')
}

onMounted(() => {
  nextTick(() => {
    try {
      initEchartsFun()
    } catch (error) {
      console.log(error)
    }
  })
})

onUnmounted(() => {
  if (myChart) {
    myChart.dispose()
  }
  observer.disconnect()
})
function initEchartsFun() {
  const DOM = document.getElementById(Id)
  DOM.style.width = content.value.offsetWidth
  DOM.style.height = content.value.offsetHeight
  observer.observe(DOM)
  myChart = echarts.init(DOM)

  myChart.on('click', clickHandler)
  myChart.on('finished', finishedHandler)
  // window.onresize = resizeHandler
}
// 点击全屏
const fvisible = ref(false)
function handleFullScreen() {
  fvisible.value = !fvisible.value
  themeProp.value = fvisible.value ? '#000' : '#fff'
  if (props.isMobile) {
    themeProp.value = '#fff'
  }
  nextTick(() => {
    initEchartsFun()
    http(oldParams.res, oldParams.unit, oldParams.timeParams)
  })
}
function handleFullscreen() {
  if (myChart) myChart.resize()
}
// 点击下载
function handleExportChartData() {
  emits('exportChartData')
}

// 点击刷新图表
async function handleRefresh() {
  emits('emitRefresh')
}

defineExpose({
  http,
  chart: getCurrentChart,
  setLoading,
  downloadData,
  reset
})
</script>

<style lang="scss" scoped>
.chart-box {
  width: 100%;
}
.data-zoom {
  height: 50px;
}
#content {
  width: 100%;
  height: 100%;
  position: relative;
  img {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }

  .echartsToolBox {
    // border: red solid 1px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    position: absolute;
    top: 0px;
    right: 0px;
    z-index: 9;
    padding-top: 10px;
    padding-right: 10px;

    .iconRefresh {
      width: 12px;
      height: 12px;
      cursor: pointer;
      font-size: 12px;
      color: #999;
      border: 1px solid #999;
      opacity: 0.5;
      border-radius: 4px;
      padding: 3px;
      background: rgba(255, 255, 255, 0.08);
    }
    .iconRefresh:hover {
      color: #fff;
      opacity: 1;
      border: 1px solid #fff;
    }
  }
}
</style>
